package cn.modfun.web.core.controller;


import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import cn.modfun.web.core.annotation.Column;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;

import com.alibaba.fastjson.JSON;

import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.Setting;
import cn.modfun.common.lang.MapUtils;
import cn.modfun.common.lang.StringUtils;
import cn.modfun.web.core.annotation.Column;

/**
 * 服务层注解实现
 * @author LinCH
 *
 */
public abstract class BaseController extends com.jfinal.core.Controller {
	/**
	 * 分页模式(start 行模式 page 页模式)
	 */
	private static String PAGING_MODE = "start";
	/**
	 * 查询的start开始标识
	 */
	private static String PAGING_START_KEY = "start";
	/**
	 * 查询的limit开始标识
	 */
	private static String PAGING_LIMIT_KEY = "limit";
    
	static{
		Setting setting = new Setting("config/jfinal.txt");
		PAGING_MODE = setting.getByGroup("PAGING_MODE", "cn.modfun.web.core.controller.BaseController");
		PAGING_START_KEY = setting.getByGroup("PAGING_START_KEY", "cn.modfun.web.core.controller.BaseController");
		PAGING_LIMIT_KEY = setting.getByGroup("PAGING_LIMIT_KEY", "cn.modfun.web.core.controller.BaseController");
	}
	
	public static boolean isAjax(HttpServletRequest request){
		if((request.getHeader("X-Requested-With") != null && request.getHeader("X-Requested-With").contains("XMLHttpRequest"))){
			if(request.getHeader("accept") == null || request.getHeader("accept").contains("application/json")){
				return true;
			}
		}
		if(StringUtils.isNotBlank(request.getParameter("_dataType")) && request.getParameter("_dataType").equals("json")){
			return true;
		}
		return false;
	}

	public boolean isAjax(){
		return isAjax(getRequest());
	}
    /**
     * 获得请求体
     * @return
     */
    public String getRequestBody(){
    	try {
			return IOUtils.toString(getRequest().getInputStream(), "UTF-8");
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
    }
    /**
     * 获得请求体的map对象
     * @return
     */
	@SuppressWarnings("unchecked")
	public Map<String,Object> getRequestBodyForMap(){
    	String str = getRequestBody();
    	if(str==null){
    		return null;
    	}else{
    		return JSON.parseObject(str, Map.class);
    	}
    }
	
	/**
	 * 获得请求中的参数
	 * @param request
	 * @return
	 */
	public Map<String,Object> getParams(){
		Map<String,Object> params = new HashMap<String,Object>();
		for (Map.Entry<String, String[]> entry : getRequest().getParameterMap().entrySet()) {
			if(entry.getValue()!=null){
				if(entry.getValue().length == 1){
					params.put(entry.getKey(), entry.getValue()[0]);
				}else if(entry.getValue().length > 1){
					params.put(entry.getKey(), entry.getValue());
				}
			}
		}
		return params;
	}
	
	/**
	 * 获得带分页的请求参数
	 * @param request
	 * @return
	 */
	public Map<String,Object> getPageParams(){
		Map<String,Object> params = getParams();
		/**
		 * 获取分页模式
		 * rows 代表已传递参数为 start limit
		 * page 代表传递的参数为 pageNo limit
		 */
		if("rows".equals(PAGING_MODE)){
			params.put("start", MapUtils.getInteger(params, PAGING_START_KEY,0));
			params.put("limit", MapUtils.getInteger(params, PAGING_LIMIT_KEY,10));
		}else if("page".equals(PAGING_MODE)){
			/* 执行转换 (page - 1) * pageRows + 1, page * pageRows */
			int pageNo = MapUtils.getInteger(params, PAGING_START_KEY,1);
			int limit = MapUtils.getInteger(params, PAGING_LIMIT_KEY,10);
			params.put("start", (pageNo - 1) * limit);
			params.put("limit", limit);
		}
		return params;
	}
	
	public String getIpAddress(){
		return getIpAddress(getRequest());
	}
	
	public String getIpAddress(HttpServletRequest request) {
		String ipAddress = request.getHeader("x-forwarded-for");
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getRemoteAddr();
			if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
				// 根据网卡取本机配置的IP
				InetAddress inet = null;
				try {
					inet = InetAddress.getLocalHost();
				} catch (UnknownHostException e) {
					e.printStackTrace();
				}
				ipAddress = inet.getHostAddress();
			}
		}
		// 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
		if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
															// = 15
			if (ipAddress.indexOf(",") > 0) {
				ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
			}
		}
		return ipAddress;
	}
	/**
	 * 获得列模型
	 * @param modelClass
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getColumnModel(Class<T> modelClass) {
		/* 实例化类 */
		Object temp = null;
		try {
			temp = modelClass.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
			return null;
		}
		/* 获得类中包含@Column的列 */
		Field[] fields = modelClass.getDeclaredFields();
		Method setMethod = null;
		try {
			setMethod = modelClass.getMethod("set", String.class,Object.class);
		} catch (NoSuchMethodException | SecurityException e) {
			e.printStackTrace();
			return null;
		}
		for(Field f : fields){
			Column col = f.getAnnotation(Column.class);
			if(col!=null){
				String field_name = StrUtil.isBlank(col.field())?f.getName():col.field();
				String field_type = f.getType().getSimpleName().toLowerCase();
				/* 若列在请求中不存在就不执行设值方法 */
				if(getPara(field_name)==null){
					continue;
				}
				/* int */
				if("int".equals(field_type) || "integer".equals(field_type)){
					try {
						setMethod.invoke(temp, field_name,getParaToInt(field_name));
						continue;
					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
						e.printStackTrace();
					}
				}
				if("string".equals(field_type)){
					try {
						setMethod.invoke(temp, field_name,getPara(field_name));
						continue;
					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
						e.printStackTrace();
					}
				}
				if("double".equals(field_type)){
					try {
						setMethod.invoke(temp, field_name,Double.parseDouble(getPara(field_name)));
						continue;
					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
						e.printStackTrace();
					}
				}
				if("float".equals(field_type)){
					try {
						setMethod.invoke(temp, field_name,Float.parseFloat(getPara(field_name)));
						continue;
					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
						e.printStackTrace();
					}
				}
				if("boolean".equals(field_type)){
					try {
						setMethod.invoke(temp, field_name,getParaToBoolean(field_name));
						continue;
					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
						e.printStackTrace();
					}
				}
				if("long".equals(field_type)){
					try {
						setMethod.invoke(temp, field_name,getParaToLong(field_name));
						continue;
					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
						e.printStackTrace();
					}
				}
				if("date".equals(field_type)){
					try {
						/* 判断参数 */
						if(StringUtils.isNotBlank(getPara(field_name))){
							setMethod.invoke(temp, field_name,DateTime.parse(getPara(field_name), DateTimeFormat.forPattern(col.dateFormat())).toString(col.dateFormat()));
						}
						continue;
					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return temp == null ? null : (T) temp;
	}
	/**
	 * 判断浏览器类型
	 * @return
	 */
	public String getBrowserType(){
		String userAgent = getRequest().getHeader("User-Agent").toLowerCase();
		String type = null;
		if(userAgent.indexOf("micromessenger")>0){
			return "weixin";
		}else if(userAgent.indexOf("alipayclient")>0){
			return "alipay";
		}
		return type;
	}
	
	
	@SuppressWarnings("unchecked")
	public static <T> T[] unique(Class<T> cls,T[] arr){
		if(arr == null || arr.length == 0){return null;}
		Set<T> set = new HashSet<T>();
		for(int i = 0,ln = arr.length ; i<ln;i++){
			set.add(arr[i]);
		}
		return set.toArray((T[])Array.newInstance(cls, set.size()));
	}
	/*public static Object[] unique(Object [] arr){
        //实例化一个set集合
        Set<Object> set = new HashSet<Object>();
        //遍历数组并存入集合,如果元素已存在则不会重复存入
        for (int i = 0; i < arr.length; i++) {
            set.add(arr[i]);
        }
        //返回Set集合的数组形式
        return set.toArray();
    }
	public Object[] getParaValuesForUnique(String name){
		String[] arr = getParaValues(name);
		if(arr!=null){
			return unique(arr);
		}
		return null;
	}*/
	
}